package com.cah.project.module.generate.service.helper;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import com.cah.project.conf.GenConfig;
import com.cah.project.enums.YesOrNoEnum;
import com.cah.project.exception.BusinessException;
import com.cah.project.module.generate.domain.bo.GenNameBO;
import com.cah.project.module.generate.domain.bo.GenTableBO;
import com.cah.project.module.generate.domain.bo.GenTableFieldBO;
import com.cah.project.module.generate.domain.entity.GenTableColumnEntity;
import com.cah.project.module.generate.domain.entity.GenTableEntity;
import com.cah.project.module.generate.domain.vo.GenTableInfo;
import com.cah.project.module.generate.domain.vo.out.DbTableColumnList;
import com.cah.project.module.generate.domain.vo.out.DbTableList;
import com.cah.project.module.generate.enums.ColumnTypeEnum;
import com.cah.project.module.generate.enums.GenTypeEnum;
import com.cah.project.module.generate.enums.QueryTypeEnum;
import com.cah.project.module.generate.enums.TemplateCategoryEnum;
import com.cah.project.module.generate.enums.TemplateModelEnum;
import com.cah.project.module.generate.service.IGenTableColumnService;
import com.cah.project.module.generate.service.IGenTableService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 功能描述: 代码生成帮助类 <br/>
 */
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GenHelper {

    private final IGenTableService genTableService;
    private final IGenTableColumnService genTableColumnService;

    /**
     * 功能描述: 批量初始化 生成表定义 内容 <br/>
     *
     * @param dbTableList 数据库表信息列表
     * @return "java.util.List<com.cah.project.module.generate.domain.entity.GenTableEntity>"
     */
    public List<GenTableEntity> initGenTableEntityList(List<DbTableList> dbTableList) {
        return dbTableList.stream().map(this::initGenTableEntity).collect(Collectors.toList());
    }

    /**
     * 功能描述: 初始化 生成表定义 内容 <br/>
     *
     * @param dbTable 数据库表信息
     * @return "com.cah.project.module.generate.domain.entity.GenTableEntity"
     */
    public GenTableEntity initGenTableEntity(DbTableList dbTable) {
        GenTableEntity entity = new GenTableEntity();
        entity.setTableName(dbTable.getTableName());
        entity.setTableComment(dbTable.getTableComment());
        // 自动填充内容
        // 设置 表前缀
        entity.setPrefix(GenConfig.getAutoRemovePre() ? GenConfig.getTablePrefix() : "");
        // 设置 类名，为表名（根据是否需要去除前缀，再转成驼峰命名，并且首字母大写）
        entity.setClassName(StrUtil.upperFirst(StrUtil.toCamelCase(entity.getTableName().replace(GenConfig.getTablePrefix(), ""))));
        // 设置 使用的模板
        entity.setTplCategory(TemplateCategoryEnum.CURD.getCode());
        // 设置 生成包路径
        entity.setPackageName(GenConfig.getPackageName());
        // 设置 生成模块名
        entity.setModuleName(GenConfig.getModuleName());
        // 设置 业务名（businessName为moduleName下面的子包，默认没有，直接跟controller、service、mapper等）
        entity.setBusinessName(null);
        // 设置 功能（默认为表描述）
        entity.setFunctionName(entity.getTableComment());
        // 设置 作者
        entity.setFunctionAuthor(GenConfig.getAuthor());
        // 设置 代码生成方式
        entity.setGenType(GenTypeEnum.ZIP.getIndex());
        // 设置 生成路径
        entity.setGenPath(GenConfig.getGenPath());
        return entity;
    }

    /**
     * 功能描述: 转换出需要生成的模型 <br/>
     *
     * @param tableId 定义表ID
     * @return "com.cah.project.module.generate.domain.bo.GenTableBO"
     */
    public GenTableBO getGenTableBOById(Long tableId) {
        GenTableEntity genTableEntity = genTableService.getById(tableId);
        List<GenTableColumnEntity> genTableColumnEntityList = genTableColumnService.getByTableId(tableId);
        // 转换
        GenTableBO tableBO = initGenTableBO(genTableEntity);
        // 设置命名
        GenNameBO nameBO = initGenNameBO(tableBO.getPackageName(), tableBO.getModuleName(), tableBO.getBusinessName(), tableBO.getClassName());
        tableBO.setGenName(nameBO);
        // 设置公共字段
        tableBO.setCommonColumns(ListUtil.empty());

        // 如果有子表，设置子表内容

        // ...
        // 转换并设置字段内容
        List<GenTableFieldBO> fieldBOList = initGenTableFieldBOList(genTableColumnEntityList);
        tableBO.setColumns(fieldBOList);
        // 设置字段导入包
        tableBO.setImportPackages(getFieldJavaPackage(fieldBOList));
        return tableBO;
    }

    /**
     * 功能描述: 初始化命名 <br/>
     *
     * @param packageName 包名
     * @param moduleName 模块名
     * @param businessName 业务名
     * @param className 类名
     * @return "com.cah.project.module.generate.domain.bo.GenNameBO"
     */
    private GenNameBO initGenNameBO(String packageName, String moduleName, String businessName, String className) {
        GenNameBO bo = new GenNameBO();
        // 包路径
        String packageFullName = packageName + (StrUtil.isEmpty(moduleName) ? "" : ".module." + moduleName) + (StrUtil.isEmpty(businessName) ? "" : "." + businessName);
        Field[] fields = GenNameBO.class.getDeclaredFields();
        try {
            for(Field field : fields) {
                field.setAccessible(true);
                TemplateModelEnum modelEnum = Optional.of(TemplateModelEnum.valueOf(StrUtil.toUnderlineCase(field.getName()).toUpperCase()))
                        .orElseThrow(() -> new BusinessException("查找不到"));
                field.set(bo, modelEnum.getInstance(packageFullName, className));
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return bo;
    }

    /**
     * 功能描述: 获取java的引包 <br/>
     *
     * @param fieldBOList 字段列表
     * @return "java.util.List<java.lang.String>"
     */
    private List<String> getFieldJavaPackage(List<GenTableFieldBO> fieldBOList) {
        List<String> importPackage = ListUtil.list(false);
        for(GenTableFieldBO fieldBO : fieldBOList) {
            if("Date".equals(fieldBO.getJavaType())) {
                importPackage.add(Date.class.getName());
            }
            if("BigDecimal".equals(fieldBO.getJavaType())) {
                importPackage.add(BigDecimal.class.getName());
            }
            if("LocalDate".equals(fieldBO.getJavaType())) {
                importPackage.add(LocalDate.class.getName());
            }
        }
        return importPackage.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 功能描述: 批量初始化 生成表字段定义 内容 <br/>
     *
     * @param dbTableColumnList 数据库表字段列表
     * @return "java.util.List<com.cah.project.module.generate.domain.entity.GenTableColumnEntity>"
     */
    public List<GenTableColumnEntity> initGenTableColumnEntityList(Map<String, GenTableEntity> tableEntityMap, List<DbTableColumnList> dbTableColumnList) {
        return dbTableColumnList.stream()
                .map(db -> initGenTableColumnEntity(tableEntityMap, db))
                .sorted(Comparator.comparing(GenTableColumnEntity::getSort))
                .collect(Collectors.toList());
    }

    /**
     * 功能描述: 初始化 生成表字段定义 内容 <br/>
     *
     * @param dbTableColumn 数据库表字段
     * @return "com.cah.project.module.generate.domain.entity.GenTableColumnEntity"
     */
    private GenTableColumnEntity initGenTableColumnEntity(Map<String, GenTableEntity> tableEntityMap, DbTableColumnList dbTableColumn) {
        GenTableColumnEntity entity = new GenTableColumnEntity();
        entity.setTableId(tableEntityMap.get(dbTableColumn.getTableName()).getId());
        entity.setColumnName(dbTableColumn.getColumnName());
        entity.setColumnComment(dbTableColumn.getColumnComment());
        entity.setColumnType(dbTableColumn.getColumnType().replace("unsigned", "").trim());
        entity.setIsPk(dbTableColumn.getIsPk());
        entity.setPkType(dbTableColumn.getPkType());
        entity.setIsRequired(dbTableColumn.getIsRequired());
        entity.setSort(dbTableColumn.getSort());
        // 自动填充内容
        // 设置 java字段名，使用驼峰命名法
        entity.setJavaField(StrUtil.toCamelCase(entity.getColumnName()));
        // 设置 java类型
        entity.setJavaType(ColumnTypeEnum.getJavaType(entity.getColumnType()));
        // 设置 html控件类型
        entity.setHtmlType(ColumnTypeEnum.getHtmlType(entity.getColumnType()));
        // 设置 编辑字段，主键必须存在，排除系统字段
        entity.setIsEdit(entity.getIsPk() == 1 ? 1 : GenConfig.getSysFields().contains(entity.getJavaField()) ? 0 : 1);
        // 设置 列表字段，主键必须存在
        entity.setIsList(entity.getIsPk() == 1 ? 1 : GenConfig.getSysFields().contains(entity.getJavaField()) ? 0 : 1);
        // 设置 查询字段
        entity.setIsQuery(GenConfig.getSysFields().contains(entity.getJavaField()) ? 0 : 1);
        // 设置 查询方式（如果是查询字段，才设置该内容）
        entity.setQueryType(entity.getIsQuery() == 1 ? QueryTypeEnum.EQ.getCode() : null);
        // 其他设置。。。（智能设置：如通过字段名命名，重新设置内容）

        return entity;
    }

    /**
     * 功能描述: 保存校验 <br/>
     */
    public void check(GenTableInfo info) {


    }

    /**
     * 功能描述: 表转换 <br/>
     *
     * @param genTableEntity 表定义实体
     * @return "com.cah.project.module.generate.domain.bo.GenTableBO"
     */
    public GenTableBO initGenTableBO(GenTableEntity genTableEntity) {
        GenTableBO genTableBO = new GenTableBO();
        genTableBO.setTableName( genTableEntity.getTableName() );
        genTableBO.setTableComment( StrUtil.replace(genTableEntity.getTableComment(), "\"", "'") );
        genTableBO.setSubTableName( genTableEntity.getSubTableName() );
        genTableBO.setSubTableFkName( genTableEntity.getSubTableFkName() );
        genTableBO.setPrefix( genTableEntity.getPrefix() );
        genTableBO.setClassName( genTableEntity.getClassName() );
        genTableBO.setTplCategory( genTableEntity.getTplCategory() );
        genTableBO.setPackageName( genTableEntity.getPackageName() );
        genTableBO.setModuleName( genTableEntity.getModuleName() );
        genTableBO.setBusinessName( genTableEntity.getBusinessName() );
        genTableBO.setFunctionName( genTableEntity.getFunctionName() );
        genTableBO.setFunctionAuthor( genTableEntity.getFunctionAuthor() );
        genTableBO.setGenType( genTableEntity.getGenType() );
        genTableBO.setGenPath( genTableEntity.getGenPath() );
        genTableBO.setOptions( genTableEntity.getOptions() );
        genTableBO.setParentMenuId( genTableEntity.getParentMenuId() );
        genTableBO.setParentMenuName( genTableEntity.getParentMenuName() );
        return genTableBO;
    }

    /**
     * 功能描述: 全部字段转换 <br/>
     *
     * @param list 字段定义实体列表
     * @return "java.util.List<com.cah.project.module.generate.domain.bo.GenTableFieldBO>"
     */
    public List<GenTableFieldBO> initGenTableFieldBOList(List<GenTableColumnEntity> list) {
        if(CollectionUtil.isNotEmpty(list)) {
            return list.stream().map(this::toGenTableFieldBO).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    /**
     * 功能描述: 单字段转换 <br/>
     *
     * @param entity 字段定义实体
     * @return "com.cah.project.module.generate.domain.bo.GenTableFieldBO"
     */
    private GenTableFieldBO toGenTableFieldBO(GenTableColumnEntity entity) {
        GenTableFieldBO genTableFieldBO = new GenTableFieldBO();
        genTableFieldBO.setColumnName( entity.getColumnName() );
        genTableFieldBO.setColumnComment( StrUtil.replace(entity.getColumnComment(), "\"", "'") );
        genTableFieldBO.setColumnType( entity.getColumnType() );
        genTableFieldBO.setJavaType( entity.getJavaType() );
        genTableFieldBO.setJavaField( entity.getJavaField() );
        genTableFieldBO.setIsPk(YesOrNoEnum.judge(entity.getIsPk()));
        genTableFieldBO.setPkType( entity.getPkType() );
        switch (genTableFieldBO.getPkType()) {
            case 0 : genTableFieldBO.setIdType("AUTO"); break;
            case 1 : genTableFieldBO.setIdType("NONE"); break;
            case 2 : genTableFieldBO.setIdType("INPUT"); break;
            case 3 : genTableFieldBO.setIdType("ID_WORKER"); break;
            case 4 : genTableFieldBO.setIdType("UUID"); break;
            case 5 : genTableFieldBO.setIdType("ID_WORKER_STR"); break;
            default:
                genTableFieldBO.setIdType(""); break;
        }
        genTableFieldBO.setIsRequired(YesOrNoEnum.judge(entity.getIsRequired()) );
        genTableFieldBO.setIsInsert(YesOrNoEnum.judge(entity.getIsInsert()));
        // 主键必须在编辑中
        genTableFieldBO.setIsEdit(genTableFieldBO.getIsPk() || YesOrNoEnum.judge(entity.getIsEdit()) );
        // 主键必须在列表中
        genTableFieldBO.setIsList(genTableFieldBO.getIsPk() || YesOrNoEnum.judge(entity.getIsList()) );
        genTableFieldBO.setIsQuery(YesOrNoEnum.judge(entity.getIsQuery()) );
        genTableFieldBO.setQueryType( entity.getQueryType() );
        genTableFieldBO.setHtmlType( entity.getHtmlType() );
        genTableFieldBO.setDictType( entity.getDictType() );
        genTableFieldBO.setSort( entity.getSort() );
        return genTableFieldBO;
    }


}
